require "utils"
require "system"

attacks={}
attacks.formula = function(character,a,b,matterorshape,lightordark,selforother)
  return math.floor(  (character.stats[a]+(character.stats[b]/2))
           +(matterorshape*character.bonus.matterorform)
           +(lightordark*character.bonus.lightordark)
           +(selforother*character.bonus.selforother)
        )
end

--physical combat
attacks.melee = function(character)
  return attacks.formula(character,"body","soul",1,1,1)
end
--combat at distance
attacks.ranged = function(character)
  return attacks.formula(character,"body","mind",1,1,-1)
end
--creative magic
attacks.white = function(character)
  return attacks.formula(character,"mind","soul",-1,1,-1)
end
--destructive magic
attacks.black = function(character)
  return attacks.formula(character,"mind","body",1,-1,1)
end
--soul over self
attacks.id = function(character)
  return attacks.formula(character,"soul","body",-1,-1,1)
end
--soul over others(community)
attacks.ego = function(character)
  return attacks.formula(character,"soul","mind",-1,-1,-1)
end


defenses = {}
defenses.formula = function(character,a,matterorform,lightordark,selforother)
  return math.floor((character.stats[a])
           +(matterorform*character.bonus.matterorform)
           +(lightordark*character.bonus.lightordark)
           +(selforother*character.bonus.selforother)
         )
end

defenses.melee = function(character)
  return defenses.formula(character,"body",1,1,1)
end
defenses.ranged = function(character)
  return defenses.formula(character,"body",1,1,-1)
end
defenses.white = function(character)
  return defenses.formula(character,"mind",-1,1,-1)
end
defenses.black = function(character)
  return defenses.formula(character,"mind",1,-1,1)
end
defenses.id = function(character)
  return defenses.formula(character,"soul",-1,-1,1)
end
defenses.ego = function(character)
  return defenses.formula(character,"soul",-1,-1,-1)
end

status = {}
status.dependson = {}
status.dependson.melee  = "stamina"
status.dependson.ranged = "stamina"
status.dependson.white  = "faculty"
status.dependson.black  = "faculty"
status.dependson.id     = "virtue"
status.dependson.ego    = "virtue"

status.dependson.stamina = "body"
status.dependson.faculty = "mind"
status.dependson.virtue  = "soul"

status.current = function(character,parameter)
  return (character.status[parameter])
end
status.limit = function(character,parameter)
  return (100-character.stats[status.dependson[parameter]]*2)
end
status.mod = function(character,parameter,x)
  if(x<0)then
    character.status.lastdrain=step
  end
  if (character.status[parameter]==0) then
    if(x>0)then
      character.status[parameter]=character.status[parameter]+1
    end  
  else  
    character.status[parameter]=character.status[parameter]+x
  end  
  if status.current(character,parameter)<=0 then
    event(character,{"exhausted",parameter})
    character.status.stamina=0
  elseif character.status[parameter]<=status.limit(character,parameter) then
    event(character,{"limit",parameter})
  elseif status.current(character,parameter)>=100 then
    character.status[parameter]=100
  end
  event(character,{"changed",parameter,character.status[parameter]},"why")
  return character.status.stamina
end

event = function(who,what,why)
  printf("%s[step:%i]|%s|%s|%s|%s",now,step,"here",tostring(who),tostring(what),tostring(why or ""))
  if (what[1]=="exhausted") then
    continue = false
  end
  if (what[1]=="damaged") then
    table.insert(damageaccounting,what[2])
  end
  --do an on event check
end

skills = {}
skills.dependson = {}
skills.dependson["acrobatic"] = "body"
skills.dependson["athletic"] = "body"
skills.dependson["nimble"] = "body"
skills.dependson["stealth"] = "body"
skills.dependson["toughness"] = "body"

skills.dependson["alert"] = "mind"
skills.dependson["sharp"] = "mind"
skills.dependson["studious"] = "mind"
skills.dependson["techie"] = "mind"
skills.dependson["naturalist"] = "mind"

skills.dependson["cautious"] = "soul"
skills.dependson["wild"] = "soul"
skills.dependson["trustworthy"] = "soul"
skills.dependson["tricky"] = "soul"
skills.dependson["creative"] = "soul"

skills.current = function(character,skill)
  return character.stats[skills.dependson[skill]] + (character.skills[skill] or 0)
end

skills.mod = function(character,skill,x)
  character.skills[skill] = (character.skills[skill] or 0)+x 
  return character.skills[skill]
end


dice ={}
dice.d100 = function()
  return rand()*100
end

actions = {}
actions.attack = function(actor,target,attack,defense)
  local att = attacks[attack](actor)
  local def = defenses[defense](target)
  local die = dice.d100()
  local result = 0
  local critical = 1
  if (die > (100-(att/5))) then
    --critical
    event(actor,{"critical",target})
    result = math.floor((att+100)/2-def)
  else
    result = math.floor((att+die+dice.d100()+dice.d100())/4-def) 
  end
  if result > 0 then
    --deal that ammount of damage
    local damage = math.floor( result )
    event(actor,{"attacked",target})
    event(target,{"damaged",damage},actor)
    status.mod(target,status.dependson[defense],-result)
  else
    event(actor,{"missed",target})
  end
end

actions.regenerate = function(character)
  if(step>(character.status.lastdrain+3)) then
    if status.current(character,"stamina")<100 then
      event(character,{"regenerated"},"natural healing") 
      status.mod(character,"stamina",25)
    end  
    if status.current(character,"faculty")<100 then
      event(character,{"regenerated"},"natural healing")
      status.mod(character,"faculty",25)
    end
    if status.current(character,"virtue")<100 then
      event(character,{"regenerated"},"natural healing")
      status.mod(character,"virtue",25)
    end
  end  
end

actions.update = function(character)
  actions.regenerate(character)
  if (character == charA) then
    actions.attack(character,charB,"melee","melee")
  else
    actions.attack(character,charA,"melee","melee")
  end  
end

update = function()
  step = step + 1
  for k,v in ipairs(characters) do
    actions.update(v)
  end
end

totalbattles = 1
battles = totalbattles
results = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
damageaccounting = {}

while battles > 0 do
  starttime = now
  dofile".\\temp\\characters.lua"
  step = 0
  continue = true
  while continue do
    update()
  end
  results[step]=(results[step] or 0)+1
  battles = battles -1
end

print(starttime,"->",now)
for k,v in pairs(results) do
  if v ~= 0 then
    print(k,v,v/totalbattles)
  end  
end

buckets = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
for k,v in pairs(damageaccounting) do
  --print(v)
  buckets[math.floor(v/5)] = (buckets[math.floor(v/5)] or 0) + 1
end  

print("damage table (n = %i)",#damageaccounting)
for k,v in pairs(buckets) do
  print(k*5,v,(v/#damageaccounting))
end

print(attacks.melee(charA))
print(attacks.ranged(charA))
print(attacks.white(charA))
print(attacks.black(charA))
print(attacks.id(charA))
print(attacks.ego(charA))    
